﻿using ManageSystem.IRepository;
using ManageSystem.IService;
using ManageSystem.Model;
using ManageSystem.Repository;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;

namespace ManageSystem.Service
{
    public class IncomeStreamService : BaseService<IncomeStream>, IIncomeStreamService
    {
        // repository manager
        public IIncomeStreamRepository incomeStreamDal = new IncomeStreamRepository();


        public Task<List<IncomeStream>> QueryIncomeStreamByProjectGuid(string projectGuid)
        {
            return incomeStreamDal.QueryIncomeStreamByProjectGuid(projectGuid);
        }

        // 添加或者更新、删除收入流水时，对项目的已到账、未到账金额和落地机构、合作方的分成进行处理
        public async Task<Project> DealWithIncomeStreamsOfProject(IncomeStream incomeStream, Project projectToBeUpdated, string mode)
        {
            // todo 统一改成先减去原来的分成再加上现在的分成
            // 计算新入账金额和旧的差值。如果旧的为0，说明此时正在录入收入流水或者删除项目.如果正在删除项目，把incomeBias变成incomeAmount的相反数，后面的代码不需要更改
            decimal incomeBias = mode != "delete" ? incomeStream.incomeAmount - incomeStream.oldIncomeAmount : incomeStream.incomeAmount * -1;

            // 更新已到账和未到账金额
            projectToBeUpdated.paidAmount += incomeBias;
            projectToBeUpdated.unpaidAmount -= incomeBias;

            // 解析落地机构和合作方json字符串
            // todo client
            List<LandingAgency> clients = JsonConvert.DeserializeObject<List<LandingAgency>>(projectToBeUpdated.clients);
            List<LandingAgency> landingAgencies = JsonConvert.DeserializeObject<List<LandingAgency>>(projectToBeUpdated.landingAgencies);
            List<Partner> partners = JsonConvert.DeserializeObject<List<Partner>>(projectToBeUpdated.partners);

            // 解析收入流水保存的分成金额字符串
            // todo client
            List<LandingAgency> incomeStreamClients = JsonConvert.DeserializeObject<List<LandingAgency>>(incomeStream.clients);
            List<LandingAgency> incomeStreamLandingAgencies = JsonConvert.DeserializeObject<List<LandingAgency>>(incomeStream.landingAgencies);
            List<Partner> incomeStreamPartners = JsonConvert.DeserializeObject<List<Partner>>(incomeStream.partners);

            // 该收入流水现在所有落地机构分成的和
            decimal totalLandingAgencyAmounts = 0;
            // 对项目的落地机构和技术方，减掉之前计算的流水的落地机构和技术方分成，后面再加上新的
            for (int i = 0; i < landingAgencies.Count; ++i)
            {
                if (mode != "add")
                {
                    landingAgencies[i].shareAmount -= incomeStreamLandingAgencies[i].shareAmount;
                }
                if (mode != "delete")
                {
                    // -------------------0.01---------------------
                    // 重新计算当前收入流水的第[i]个落地机构的分成
                    incomeStreamLandingAgencies[i].shareAmount = incomeStream.incomeAmount * incomeStreamLandingAgencies[i].shareRadio * 0.01M;
                    // 累加到项目的第[i]个落地机构的分成中
                    landingAgencies[i].shareAmount += incomeStreamLandingAgencies[i].shareAmount;
                    // 累加该收入流水现在所有落地机构分成的和
                    totalLandingAgencyAmounts += incomeStreamLandingAgencies[i].shareAmount;
                }
            }
            // todo client
            decimal totalClientAmounts = 0;
            // 对项目的委托方，减掉之前计算的流水委托方分成，后面再加上新的
            for (int i = 0; i < clients.Count; ++i)
            {
                if (mode != "add")
                {
                    clients[i].shareAmount -= incomeStreamClients[i].shareAmount;
                }
                if (mode != "delete")
                {
                    // -------------------0.01---------------------
                    // 和落地机构一样
                    incomeStreamClients[i].shareAmount = incomeStream.incomeAmount * incomeStreamClients[i].shareRadio * 0.01M;
                    clients[i].shareAmount += incomeStreamClients[i].shareAmount;
                    totalClientAmounts += incomeStreamClients[i].shareAmount;
                }
            }

            // 该收入流水现在所有技术合作方分成的和
            decimal totalPartnerAmounts = 0;
            for (int i = 0; i < partners.Count; ++i)
            {
                if (mode != "add")
                {
                    partners[i].shareAmount -= incomeStreamPartners[i].shareAmount;
                }
                if (mode != "delete")
                {
                    // 对按公式计算的需要减去一个bias
                    // todo client
                    // 删除了学院食宿 交通费
                    decimal bias = partners[i].caculation == "比例" ? 0 : totalLandingAgencyAmounts + totalClientAmounts;
                    // 与落地机构的计算同理
                    // -------------------0.01---------------------
                    incomeStreamPartners[i].shareAmount = (incomeStream.incomeAmount - bias) * incomeStreamPartners[i].shareRadio * 0.01M;
                    partners[i].shareAmount += incomeStreamPartners[i].shareAmount;
                    totalPartnerAmounts += incomeStreamPartners[i].shareAmount;
                }
            }

            // 减去旧的学校管理费等
            if (mode != "add")
            {
                projectToBeUpdated.schoolManageAmount -= incomeStream.schoolManageAmount;
                projectToBeUpdated.devFundingAmount -= incomeStream.devFundingAmount;
                projectToBeUpdated.welfareAmount -= incomeStream.welfareAmount;
                projectToBeUpdated.classPayAmount -= incomeStream.classPayAmount;
            }
            if (mode != "delete")
            {
                // 对非区域项目做特殊处理
                // todo client
                decimal totalBias = projectToBeUpdated.categories != "非区域项目" ? 0 : totalLandingAgencyAmounts + totalPartnerAmounts + totalClientAmounts;
                decimal tmp = incomeStream.incomeAmount - totalBias;
                // 重新计算学校管理费等
                // -------------------0.01---------------------
                incomeStream.schoolManageAmount = tmp * projectToBeUpdated.schoolManageRadio * 0.01M;
                incomeStream.devFundingAmount = tmp * projectToBeUpdated.devFundingRadio * 0.01M;
                incomeStream.welfareAmount = tmp * projectToBeUpdated.welfareRadio * 0.01M;
                incomeStream.classPayAmount = tmp * projectToBeUpdated.classPayRadio * 0.01M;
                // 更新到项目中
                // -------------------0.01---------------------
                projectToBeUpdated.schoolManageAmount += incomeStream.schoolManageAmount;
                projectToBeUpdated.devFundingAmount += incomeStream.devFundingAmount;
                projectToBeUpdated.welfareAmount += incomeStream.welfareAmount;
                projectToBeUpdated.classPayAmount += incomeStream.classPayAmount;
            }

            // 序列化为json，
            // todo client
            projectToBeUpdated.clients = JsonConvert.SerializeObject(clients);
            projectToBeUpdated.landingAgencies = JsonConvert.SerializeObject(landingAgencies);
            projectToBeUpdated.partners = JsonConvert.SerializeObject(partners);
            incomeStream.clients = JsonConvert.SerializeObject(incomeStreamClients);
            incomeStream.landingAgencies = JsonConvert.SerializeObject(incomeStreamLandingAgencies);
            incomeStream.partners = JsonConvert.SerializeObject(incomeStreamPartners);

            // todo 更新项目的预算和支出
            // Traverse the properties
            foreach (System.Reflection.PropertyInfo p in incomeStream.GetType().GetProperties())
            {
                if (p.Name.Contains("pay") && p.Name.Length == 4)
                {
                    // 如 payM + in，对应培训项目中的预算payMin
                    string keyOfProject = p.Name + "in";
                    // get the key-value pair of 预算
                    var propertyOfProject = projectToBeUpdated.GetType().GetProperty(keyOfProject);
                    // 待更新的预算
                    decimal oldValue = Convert.ToDecimal(propertyOfProject.GetValue(projectToBeUpdated));
                    // 该收入流水中的预算（增删改都可能）
                    decimal valueOfIncomeStream = Convert.ToDecimal(p.GetValue(incomeStream));

                    // 计算预算的变化量
                    switch (mode)
                    {
                        case "delete":
                            valueOfIncomeStream *= -1;
                            break;
                        case "update":
                            IncomeStream incomeStream1 = await incomeStreamDal.QueryByPrimaryKey(incomeStream.streamID);
                            if (incomeStream1 != null)
                            {
                                // todo ???
                                valueOfIncomeStream -= Convert.ToDecimal(incomeStream1.GetType().GetProperty(p.Name.ToString()).GetValue(incomeStream1));
                            }
                            break;
                    }
                    // 更新预算
                    propertyOfProject.SetValue(projectToBeUpdated, oldValue + valueOfIncomeStream);
                }
            }

            switch (mode)
            {
                case "add":
                    // add to db
                    await incomeStreamDal.Add(incomeStream);
                    break;
                case "delete":
                    await incomeStreamDal.DeleteByPrimaryKey(incomeStream.streamID);
                    break;
                case "update":
                    await incomeStreamDal.Update(incomeStream);
                    break;
            }
            // 返回要被更新到数据库中的project
            return projectToBeUpdated;
        }

        // 删除项目时删除与其相关的收入流水
        public async Task<int> DeleteIncomeStreamByProjectGuid(string projectGuid)
        {
            return await incomeStreamDal.DeleteIncomeStreamByProjectGuid(projectGuid);
        }
    }
}
